import java.util.Random;

/**
 * Измерение производительности алгоритмов сортировки
 */
public class Benchmark {


    private final SortAlgorithm algorithm;

    public Benchmark(SortAlgorithm algorithm) {
        this.algorithm = algorithm;
    }

    private String algo() {
        return algorithm.getClass().getSimpleName();
    }

    private Random random = new Random(3141592653589793L);

    private int[] generateRandom(int size) {
        int[] a = new int[size];
        for (int i = 0; i < a.length; i++) {
            a[i] = random.nextInt();
        }
        return a;
    }

    public void benchark(final int MIN_SIZE, final int MAX_SIZE, final int STEP_MULTIPLY) {
        System.out.print(algo() + ": разогреваем JVM.");
        int[] warmup = generateRandom(MIN_SIZE);
        algorithm.sort(warmup);
        System.out.println("..готово!");

        for (int size = MIN_SIZE; size <= MAX_SIZE; size *= STEP_MULTIPLY) {
            int[] original = generateRandom(size);

            final int N_TESTS = 1 + (MAX_SIZE + size - 1) / size;
            long totalNanos = 0;
            final long start = System.nanoTime();
            for (int test = 0; test < N_TESTS; test++) {
                int[] actual = original.clone();
                algorithm.sort(actual);
            }
            totalNanos += (System.nanoTime() - start);

            final long start2 = System.nanoTime();
            for (int test = 0; test < N_TESTS; test++) {
                original.clone();
            }
            long timeForArraycopy = System.nanoTime() - start2;
            if (timeForArraycopy > 0) {
                totalNanos -= timeForArraycopy;
            }

            double timeInSeconds = totalNanos * 1.0e-9;
            System.out.println(String.format(algo() + " %8d элементов; среднее время сортировки %5d миллисек.; скорость %3.3f млн. элементов в секунду.", size, totalNanos / 1000000 / N_TESTS, (N_TESTS * size / timeInSeconds / 1.e6)));
        }
    }

    public static void main(String[] args) {
        final int MIN_SIZE = 10 * 1000;
        final int MAX_SIZE = 10 * 1000 * 1000;
        final int STEP_MULTIPLY = 10;

        new Benchmark(new InsertionSort()).benchark(1000, 10 * MIN_SIZE, 10);


        new Benchmark(new MergeSort()).benchark(MIN_SIZE, MAX_SIZE, STEP_MULTIPLY);

        new Benchmark(new QuickSort()).benchark(MIN_SIZE, MAX_SIZE, STEP_MULTIPLY);

        new Benchmark(new HeapSort()).benchark(MIN_SIZE, MAX_SIZE, STEP_MULTIPLY);

        new Benchmark(new JdkSort()).benchark(MIN_SIZE, MAX_SIZE, STEP_MULTIPLY);

    }
}
